﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LunchListCore.Entities;
using LunchListCore.Interfaces.Agents;
using LunchListCore.Interfaces.Models;

namespace LunchListAgents
{
    public class LunchAgent : ILunchAgent
    {
        protected readonly LunchListEntities _context;

        public LunchAgent(LunchListEntities context)
        {
            _context = context;
        }

        public IReservation AddReservation(IGuestId guest, IEventId eventId)
        {

			IReservation result = _context.Reservations.Add(new Reservation
                {
                    GuestId = guest.GuestId,
                    EventId = eventId.EventId,
					CreatedDateTime = DateTime.Now,
					CreatedUserId = guest.GuestId.ToString(),
					ModifiedDateTime = DateTime.Now,
					ModifiedUserId = guest.GuestId.ToString()

                });

            _context.SaveChanges();

			return result;
        }

        public IReservation RemoveReservation(IGuestId guest, IEventId lunchEvent)
        {
			IReservation result = new Reservation();

            try
            {
                var reservation = _context.Reservations.FirstOrDefault(x => x.GuestId == guest.GuestId && x.EventId == lunchEvent.EventId);

                if (reservation != null)
                {
					result = _context.Reservations.Remove(reservation);
                    _context.SaveChanges();
                }
                else
                {
                    throw new Exception("Unable to remove the guest from the event, they are not registered for it.");
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

			return result;
        }

        /// <summary>
        /// This returns a list of Guest objects
        /// </summary>
        /// <param name="lunchDate">string ='mm/dd/yyyy'</param>
        /// <returns>LIST OF Guest</returns>
        /// <remarks>Ed worked on this method.</remarks>
        public IList<IGuest> GetGuests(IEventId lunchEvent)
        {
			IList<IGuest> result;

			result = new List<IGuest>(_context.Guests
                .Join(_context.Reservations,
                x => x.GuestId,
                xm => xm.GuestId,
                (x, xm) => new { Guest = x, Reservation = xm }).
                Where(x => x.Reservation.EventId == lunchEvent.EventId).
                Select(c => c.Guest).ToList()
                );


			return result;
        }

        public Dictionary<IEvent, IList<IGuest>> GetGuestsAndEvents(DateTime eventDate)
        {
			Dictionary<IEvent, IList<IGuest>> result = new Dictionary<IEvent, IList<IGuest>>();

            IList<IEvent> events = GetEvents(eventDate);
            if (events == default(IList<IEvent>) || !events.Any())
            {
                return null;
            }

            foreach (var singleEvent in events)
            {
                IList<IGuest> guests = GetGuests(singleEvent);
				result.Add(singleEvent, guests);
            }

			return result;
        }


        public IEvent AddEvent(string eventName, DateTime eventDate, IGuestId guest, string adLogin)
        {
			IEvent result = new Event();

            try
            {
				result = _context.Events.Add(new Event
                {
					GuestId = guest.GuestId,
                    EventName = eventName,
                    EventDate = eventDate,
                    CreatedDateTime = DateTime.Now,
                    CreatedUserId = adLogin,
                    ModifiedDateTime = DateTime.Now,
                    ModifiedUserId = adLogin
                });

                _context.SaveChanges();
            }
            catch (Exception ex)
            {
                throw ex;
            }

			return result;
        }


        public IList<IEvent> GetEvents(DateTime? eventDate = null)
        {
			IList<IEvent> result;
            DateTime date = new DateTime();
            try
            {
                date = eventDate.HasValue ? (DateTime) eventDate : DateTime.Now;

                List<Event> events = new List<Event>();
                
                if (eventDate.HasValue)
                {
                    events = _context.Events.Where(x => x.EventDate.Year == date.Year
                                                            && x.EventDate.Day == date.Day
                                                            && x.EventDate.Month == date.Month).OrderByDescending(x => x.EventDate).ToList();
                }
                else
                {
					events = _context.Events.Select(x => x).OrderByDescending(x => x.EventDate).ToList();
                }

                if (events.Any())
                {
					result = new List<IEvent>(events.ToList());
                }
                else
                {
                    return null;
                    //throw new Exception("No events exist for the selected date.");
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

			return result;
        }


        public IList<DateTime> GetUpcomingEventDates()
        {

			IList<DateTime> result = new List<DateTime>();
            DateTime eventDate = DateTime.Now;

            try
            {
                IList<Event> events = _context.Events.Where(x => x.EventDate >= eventDate).ToList();
 
                if (events.Any())
                {
					result = events.Select(x =>
					    new DateTime(x.EventDate.Year, x.EventDate.Month, x.EventDate.Day)
					    ).Distinct().ToList();
                }
                else
                {
                    return null;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

			return result;
        }


        public bool DeleteEvent(int eventid)
        {
            bool result = false;            

            var evnt = _context.Events.Where(e => e.EventId == eventid);

            var reservations = _context.Reservations.Where(r => r.EventId == eventid);

            _context.Reservations.RemoveRange(reservations);

            _context.Events.RemoveRange(evnt);

            _context.SaveChanges();

            result = true;

            return result;
        }
    }
}